namespace AnalyStock.DataManage;

using static CandlePointSet;

//创建蜡烛数据集合
internal static class CandleDataSet //创建
{
    internal static bool IsAdj { get; set; } = true; //是否复权   
    internal static int AdjType { get; set; } //0:前复权，1后复权
    internal static float DoubleVolMultiples { get; set; } = 1.85f; //交易量大于上日交易量的倍值

    internal static IList<CandlePoint> CreatCandlePoints(this IList<Daily> list, PeriodType periodType)
    {
        if (list.IsNullOrEmpty())
        {
            return new List<CandlePoint>();
        }
        var _list = list.ConvertToPointsOnDaily(); //加载日交易数据到蜡烛数据集合       
        return periodType is PeriodType.Daily
            ? _list
            : _list.ConvertToPointsOnPeriod(periodType);
    }

    //转变为蜡烛线数据
    private static List<CandlePoint> ConvertToPointsOnDaily(this IList<Daily> list)
    {
        var _list = new List<CandlePoint>();
        var index = 0;
        var lastVol = list.First().Vol; //计算交易量倍量需要保存上一日的交易量
        var frontlastVol = lastVol;
        //取得复权因子，默认前复权
        var lastPowerFactor = AdjType is 0 ? list.LastOrDefault().Adj_factor : 100.0f;
        foreach (var item in list)
        {
            var factor = item.Adj_factor / lastPowerFactor;
            _list.Add(new CandlePoint
            {
                LocationIndex = index++, //索引              
                StockCode = item.Ts_code, //0 :名称                   
                Date = item.Trade_date, //1:日期
                Open = item.Open * factor, //2:open
                High = item.High * factor, //3:high
                Low = item.Low * factor, //4:low
                Close = item.Close * factor, //5:close
                Vol = item.Vol, //6:vol
                Pctchg = item.Pct_chg,
                Change = item.Change,
                AdjustPowerFactor = item.Adj_factor, //7:adj                             
                IsDoubleVol = item.Vol / lastVol >= DoubleVolMultiples ||
                              item.Vol / frontlastVol >= DoubleVolMultiples,
                CandleType = PeriodType.Daily
            });
            frontlastVol = lastVol;
            lastVol = item.Vol;
        }

        return _list;
    }

    //转变为长周期数据 周月
    private static List<CandlePoint> ConvertToPointsOnPeriod(this IList<CandlePoint> list, PeriodType periodType)
    {
        var _list = new List<CandlePoint>();
        //索引重编号，因为节假日有时一周没有交易，根据时间计算的周编号会出现编号不连续
        var index = 0;
        var lastVol = 1.00f; //计算交易量倍量需要保存上一日的交易量        
        foreach (var sectCandleSeries in GetPeriodGroups())
        {
            var point = new CandlePoint
            {
                LocationIndex = index++,
                StockCode = sectCandleSeries.First().StockCode,
                Date = sectCandleSeries.Last().Date,
                Open = sectCandleSeries.First().Open,
                Close = sectCandleSeries.Last().Close,
                High = sectCandleSeries.Max(n => n.High),
                Low = sectCandleSeries.Min(n => n.Low),
                Vol = sectCandleSeries.Sum(n => n.Vol),
                CandleType = periodType
            };
            point.IsDoubleVol = index > 1 && point.Vol / lastVol >= DoubleVolMultiples;
            point.Pctchg = index > 1
                ? ((point.Close / _list.Last().Close) - 1.0f) * 100.0f
                : 0.00f;
            lastVol = point.Vol;
            _list.Add(point);
        }

        list.Dispose();
        return _list;

        //获取期间分组系列
        IEnumerable<IGrouping<string, CandlePoint>> GetPeriodGroups()
        {
            return periodType switch
            {
                PeriodType.Weekly => list.GroupBy(n => n.Week),
                PeriodType.Monthly => list.GroupBy(n => n.Month),
                _ => throw new NotImplementedException()
            };
        }
    }
}